package com.crowdgeeks.controller;

import java.util.ArrayList;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import twitter4j.Paging;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;

import com.crowdgeeks.model.User;
import com.crowdgeeks.twitterclient.TwitterStatus;
import com.crowdgeeks.util.PMF;

@Controller
public class TwitterController {
    private Log log = LogFactory.getLog(TwitterController.class);

    private String consumerKey = "zVmhNcjLILJromtPDLIs9Q";

    private String consumerSecret = "XgcuTJegqIAnsRUHreJZd2C7ICW7xqBnzqLrDgPffA";

    @RequestMapping(value = "/twitter/timeline")
    public String timeline(HttpServletRequest request, HttpServletResponse response) {
        String goUrl = "twitter/timeline";

        String id = request.getParameter("id");

        if(id != null && !"".equals(id)) {
            PersistenceManager pm = PMF.get().getPersistenceManager();
            Query query = null;
            try {
                query = pm.newQuery(User.class);
                query.setFilter("id == idParam");
                query.declareParameters("String idParam");
                List<User> list = (List<User>) query.execute(id);

                if(list != null && list.size() > 0) {
                    User user = list.get(0);
                    log.debug("id : [" + user.getId() + "], twiterId : [" + user.getTwitterId() + "], token : [" + user.getTwitterToken() + "], secret : [" + user.getTwitterTokenSecret() + "]");

                    AccessToken accessToken = new AccessToken(user.getTwitterToken(), user.getTwitterTokenSecret());
                    Twitter twitter = new TwitterFactory().getInstance();
                    twitter.setOAuthConsumer(consumerKey, consumerSecret);

                    twitter.setOAuthAccessToken(accessToken);

                    try {
                        List<Status> l = twitter.getFriendsTimeline(new Paging(1, 20));
                        //                    TwitterStatus[] tss = new TwitterStatus[l.size()];
                        List<TwitterStatus> tss = new ArrayList<TwitterStatus>();
                        for (int i = 0; i < l.size(); i++) {
                            Status s = l.get(i);
                            TwitterStatus ts = new TwitterStatus();
                            ts.setCreatedDate(s.getCreatedAt());
                            ts.setCreatedUser(s.getUser().getScreenName());
                            ts.setId(s.getId());
                            ts.setMessage(s.getText());
                            tss.add(ts);
                        }
                        log.debug(tss.size() + " friends' timeline retrieved, page number is 1");

                        request.setAttribute("twitterStatusList", tss);
                    } catch (TwitterException te) {
                        try {
                            log.error("Failed to get friends' timeline for " + twitter.getId() + " - " + te.getMessage());
                        } catch (Exception e) {}
                    }
                } else {
                    goUrl = "redirect:/twitter/index";
                }

            } finally {
                pm.close();
            }
        }

        return goUrl;
    }

    //    private Twitter loadAccessToken(User user) {
    //        AccessToken accessToken = new AccessToken(user.getTwitterToken(), user.getTwitterTokenSecret());
    //        Twitter twitter = new TwitterFactory().getInstance();
    //        twitter.setOAuthConsumer(consumerKey, consumerSecret);
    //
    //        if(accessToken != null)
    //            twitter.setOAuthAccessToken(accessToken);
    //
    //        return twitter;
    //    }

    @RequestMapping(value = "/twitter/callback")
    public String callback(HttpServletRequest request, HttpServletResponse response) throws Exception {
        log.debug("callback");

        HttpSession session = request.getSession(false);
        if(session == null) {
            session = request.getSession(true);
            log.debug("Session is null, new session created");
        }

        String oauthToken = request.getParameter("oauth_token");
        String oauthVerifier = request.getParameter("oauth_verifier");
        if(oauthToken != null) {
            log.debug("Call back from Twitter, oauth_token [" + oauthToken + "] received");
            log.debug("Call back from Twitter, oauthVerifier [" + oauthVerifier + "] received");

            RequestToken requestToken = (RequestToken) session.getAttribute("requestToken");
            String req_token = requestToken.getToken();
            String req_secret = requestToken.getTokenSecret();

            log.debug("reqToken : [" + req_token + "]");
            log.debug("reqSecret : [" + req_secret + "]");

            log.debug("requestToken retrieved from session");
            if(req_token == null) {
                log.debug("requestToken is null");
                throw new ServletException("requestToken is null");
            }

            Twitter twitter = new TwitterFactory().getInstance();
            twitter.setOAuthConsumer(consumerKey, consumerSecret);

            //AccessToken accessToken = twitter.getOAuthAccessToken(req_token, req_secret);
            AccessToken accessToken = twitter.getOAuthAccessToken(requestToken, oauthVerifier);
            twitter.setOAuthAccessToken(accessToken);

            session.removeAttribute("requestToken");
            log.debug("requestToken removed from session");

            String cgId = (String) session.getAttribute("cgId");

            long id = twitter.verifyCredentials().getId();
            String screenName = twitter.verifyCredentials().getScreenName();

            log.debug("Access token retrieved for user " + id + " from Twitter");

            storeAccessToken(cgId, "" + id, screenName, oauthVerifier, accessToken);

            twitter.shutdown();
        }
        // Go to the update status page
        log.debug("Going to the update satus page...");

        return "redirect:/user/list";
    }

    @RequestMapping(value = "/twitter/signIn")
    public void signIn(HttpServletRequest request, HttpServletResponse response) throws Exception {
        log.debug("signIn");

        HttpSession session = request.getSession(false);
        if(session == null) {
            session = request.getSession(true);
            log.debug("Session is null, new session created");
        }

        String cgId = request.getParameter("cgId");

        log.debug("cgId [" + cgId + "]");
        log.debug("consumerKey [" + consumerKey + "]");
        log.debug("consumerSecret [" + consumerSecret + "]");

        if(cgId != null && !"".equals(cgId)) {
            Twitter twitter = new TwitterFactory().getInstance();
            twitter.setOAuthConsumer(consumerKey, consumerSecret);

            try {
                RequestToken requestToken = twitter.getOAuthRequestToken();
                String authorisationUrl = requestToken.getAuthorizationURL();

                String reqToken = requestToken.getToken();
                String reqSecret = requestToken.getTokenSecret();

                log.debug("reqToken : [" + reqToken + "]");
                log.debug("reqSecret : [" + reqSecret + "]");

                session.setAttribute("requestToken", requestToken);
                session.setAttribute("cgId", cgId);

                log.debug("requestToken saved in session");

                log.debug("Redirecting user to " + authorisationUrl);
                response.sendRedirect(authorisationUrl);
            } catch (TwitterException e) {
                log.debug("Sign in with Twitter failed - " + e.getMessage());
                throw new ServletException(e);
            }
        } else {
            response.sendRedirect("/index");
        }
    }

    private void storeAccessToken(String id, String twitterId, String twitterScreenName, String oauthVerifier, AccessToken accessToken) {
        if(accessToken == null) {
            throw new IllegalArgumentException("Access token to be saved is null");
        }

        log.debug("id : [" + id + "], token : [" + accessToken.getToken() + "], secret : [" + accessToken.getTokenSecret() + "]");

        User tid = new User(id, '$' + twitterId, twitterScreenName, accessToken.getToken(), accessToken.getTokenSecret(), oauthVerifier);

        PersistenceManager pm = PMF.get().getPersistenceManager();
        try {
            pm.makePersistent(tid);
        } finally {
            pm.close();
        }
    }

    //    private Twitter generateTwitterObjectFromSession(HttpSession session) throws ServletException {
    //        String at = (String) session.getAttribute("accessToken");
    //        String as = (String) session.getAttribute("accessSecret");
    //        log.debug("accessToken retrieved from session");
    //
    //        if(at == null) {
    //            log.debug("accessToken is null");
    //            throw new ServletException("accessToken is null");
    //        }
    //
    //        AccessToken accessToken = new AccessToken(at, as);
    //
    //        Twitter twitter = new TwitterFactory().getInstance();
    //        twitter.setOAuthConsumer(consumerKey, consumerSecret);
    //        twitter.setOAuthAccessToken(accessToken);
    //
    //        return twitter;
    //    }

    //    private void getMyLastStatusAndStoreInSession(HttpSession session) throws TwitterException, ServletException {
    //        Twitter twitter = generateTwitterObjectFromSession(session);
    //
    //        // Get last updated status and save it in session
    //        List<Status> updatesList = twitter.getUserTimeline();
    //        if(!updatesList.isEmpty()) {
    //            Status status = updatesList.get(0);
    //            session.setAttribute("lastUpdatedStatus", status.getText() + " [" + status.getCreatedAt() + "]");
    //            session.setAttribute("lastUpdatedStatusId", "" + status.getId());
    //            log.debug("Last update stored in session for Twitter user " + twitter.verifyCredentials().getId());
    //        } else {
    //            log.debug("Twitter user " + twitter.verifyCredentials().getId() + " has no update available");
    //        }
    //    }

    //    private void getFriendsTimelinesAndStoreInSession(HttpSession session, boolean isLatestTimelinesRequired) throws ServletException {
    //        if(isLatestTimelinesRequired) { // Start from page 1
    //            session.removeAttribute("friendsTimelinesPage");
    //            getFriendsTimelinesAndStoreInSession(session);
    //        }
    //    }

    //    private void getFriendsTimelinesAndStoreInSession(HttpSession session) throws ServletException {
    //        Integer p = (Integer) session.getAttribute("friendsTimelinesPage");
    //        int page = 1;
    //        if(p != null) {
    //            page = p + 1;
    //        }
    //
    //        Twitter twitter = generateTwitterObjectFromSession(session);
    //
    //        try {
    //            List<Status> l = twitter.getFriendsTimeline(new Paging(page, 20));
    //            TwitterStatus[] tss = new TwitterStatus[l.size()];
    //            for (int i = 0; i < tss.length; i++) {
    //                Status s = l.get(i);
    //                TwitterStatus ts = new TwitterStatus();
    //                ts.setCreatedDate(s.getCreatedAt());
    //                ts.setCreatedUser(s.getUser().getScreenName());
    //                ts.setId(s.getId());
    //                ts.setMessage(searchAndReplaceLink(searchAndReplaceLink(s.getText(), "http"), "https"));
    //                tss[i] = ts;
    //            }
    //            log.debug(tss.length + " friends' timeline retrieved, page number is " + page);
    //
    //            session.setAttribute("friendsTimelines", tss);
    //            session.setAttribute("friendsTimelinesPage", page);
    //        } catch (TwitterException te) {
    //            try {
    //                log.debug("Failed to get friends' timeline for " + twitter.getId() + " - " + te.getMessage());
    //            } catch (Exception e) {}
    //        }
    //    }

    //    private static String searchAndReplaceLink(String message, String protocol) {
    //        // Message returned by Twitter does not have proper HTTP(S) links
    //        // So construct them here
    //        if(message == null || protocol == null) {
    //            return message;
    //        }
    //
    //        protocol = protocol.trim();
    //        if(protocol.indexOf("://") == -1) {
    //            protocol = " " + protocol + "://";
    //        }
    //
    //        int idx1, idx2;
    //        StringBuilder sb = new StringBuilder();
    //        while ((idx1 = message.indexOf(protocol)) != -1) {
    //            sb.append(message.substring(0, idx1 + 1));
    //            message = message.substring(idx1 + 1);
    //            if((idx2 = message.indexOf(' ')) != -1) {
    //                String str = message.substring(1, idx2);
    //                sb.append("<a href=\"").append(str).append("\" target=\"_blank\">").append(str).append("</a>");
    //                message = message.substring(idx2);
    //            } else {
    //                sb.append("<a href=\"").append(message).append("\" target=\"_blank\">").append(message).append("</a>");
    //                message = "";
    //            }
    //        }
    //        sb.append(message);
    //
    //        return sb.toString();
    //    }
}
